class MyPromise {
    
    /* Promise状态定义 */
    static STATUS_PENDING = 0; // 挂起态
    static STATUS_FULFILLED = 1; // 履约态
    static STATUS_REJECTED = 2; // 毁约态

    constructor(executor) {
        /* 回调队列 + 回调入参 （JS单线程模型=每次只能有一个回调被执行） */
        this.callbacks = [];
        this.cbArg = null;

        /* 绑定执行器函数中的resolve与reject */
        this.executor = executor.bind(
            this,//当前promise实例

            //当前promise实例执行resolve时,this不变
            MyPromise.doResolve.bind(this),

            //当前promise实例执行reject时,this不变
            MyPromise.doReject.bind(this)
        );

        /* 稍后执行任务函数 执行权先让给后续的then,catch,finally */
        setTimeout(() => {
            // 执行任务前先将Promise状态设置为pending
            this.status = MyPromise.STATUS_PENDING;

            // 执行任务（任务中会resolve/doResolve或reject/doReject）
            this.executor();
        });
        
    }

    /* promise实例执行resolve */
    static doResolve(data) {
        /* 设置状态为履约态 + 设置回调时的入参 + 拉起下一次回调 */
        this.status = MyPromise.STATUS_FULFILLED;
        this.cbArg = data;

        // 拉起下一次then回调
        this.next();
    }

    /* promise实例执行reject */
    static doReject(err) {
        /* 设置状态为毁约态 + 设置回调时的错误 + 拉起下一次回调 */
        this.status = MyPromise.STATUS_REJECTED;
        this.cbArg = err;

        // 拉起下一次catch回调
        this.next();
    }

    /* 
    成功时：从回调队列头部把所有的catch驱逐
    失败时：从回调队列头部把所有的then驱逐
    */
    shiftCallbacksWithType(type) {
        while (this.callbacks.length && this.callbacks[0].type === type) {
            // 驱逐一个回调函数
            this.callbacks.shift();
        }
    }

    /* 
    从回调队列里拉取下一个适当的callback并回调之
    这是MyPromise的核心代码：递归inside! 
    */
    next() {
        /* 确定该回调哪一个callback */
        if (this.status === MyPromise.STATUS_FULFILLED) {
            // 履约时：弹光队列头部的catch回调
            this.shiftCallbacksWithType("catch");
        }

        if (this.status === MyPromise.STATUS_REJECTED) {
            // 毁约时：弹光队列头部的then回调
            this.shiftCallbacksWithType("then");
        }

        /* 如果回调队列已空，则直接结束程序 */
        if (!this.callbacks.length) {
            console.log("回调队列已空");
            return;
        }

        /* 拉取回调队列头部的回调函数（注意这里无视了type只解构出函数本身） */
        let { callback } = this.callbacks.shift();

        /* 防止回调函数中throw错误 */
        try {
            // 执行回调并拿到其结果（value或promise对象）
            let value = callback(this.cbArg);

            // 如果回调函数返回一个value 继续向下resolve(value)
            if (!(value instanceof MyPromise)) {
                MyPromise.doResolve.call(this, value);
            } else {
                // 如果回调函数返回一个Promise对象
                // 为后续所有callback悄悄置换this为新的Promise对象
                // 这里特别注意：
                // Promise对象的执行器很快就要执行起来了！因为构造器里有setTimeout(executor,0)！
                value.callbacks = this.callbacks
                // result.callbacks = this.callbacks.map(({ type, callback }) => ({
                //     type,
                //     callback: callback.bind(result),
                // }));
            }
        } catch (err) {
            // 回调函数抛出错误时相当于reject(err)
            MyPromise.doReject.call(this, err);
        }

    }

    /* 语法糖：创建一个立即resolve的Promise对象 */
    static resolve(data) {
        return new MyPromise((resolve) => resolve(data));
    }

    /* 语法糖：创建一个立即reject的Promise对象 */
    static reject(err) {
        return new MyPromise((resolve, reject) => reject(err));
    }

    /* 收集成功回调到队列 */
    then(onData) {
        // 将来一旦Promise毁约 回调队列头部的所有then回调都要弹出作废
        this.callbacks.push({ type: "then", callback: onData });
        return this;
    }

    /* 收集失败回调到队列 */
    catch(onErr) {
        // 将来一旦Promise履约 回调队列头部的所有catch回调都要弹出作废
        this.callbacks.push({ type: "catch", callback: onErr });
        return this;
    }

    /* 收集终点回调到队列（此处假设只有一个终点回调） */
    finally(onFinish) {
        this.callbacks.push({ type: "finally", callback: onFinish });
        return this;
    }
}

module.exports = MyPromise;
